home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / vol7n7.arc / PP707.ARC / LCVT.ASM < prev    next >
Assembly Source File  |  1987-12-15  |  9KB  |  266 lines

  1.         name    LCVT
  2.         title   LCVT - format 32-bit number
  3.         page    55,132
  4. ;
  5. ;
  6. ; LCVT.ASM --- Convert signed long (32-bit) integer
  7. ;              to formatted ASCII decimal string
  8. ;
  9. ; Copyright (C) 1988 Ziff Communications Co.
  10. ; PC Magazine * Ray Duncan
  11. ;
  12. ; Call with:    BH    = decimal places
  13. ;               BL    = field width
  14. ;               CH    = conversion flags
  15. ;                       bit meaning
  16. ;                        7  = 0 if left justify
  17. ;                             1 if right justify
  18. ;                        6  = 0 fill field with * 
  19. ;                               if number too large
  20. ;                             1 truncate to fit
  21. ;                        5  = 0 prefix with - only
  22. ;                             1 prefix with + or -
  23. ;                        4  = 0 pad with blanks
  24. ;                             1 pad with char in CL
  25. ;                       0-3 = reserved
  26. ;               CL    = pad character 
  27. ;                       (if bit 4 of CH is set)
  28. ;               DX:AX = 32-bit signed integer
  29. ;               DS:SI = buffer to receive string
  30. ;
  31. ; Returns:      if successful,
  32. ;               Carry = clear
  33. ;               DS:SI = formatted string
  34. ;               AX    = output field length
  35. ;
  36. ;               if error (number too large,
  37. ;               and bit 6 of CH was not set),
  38. ;               Carry = set 
  39. ;               and output buffer filled with '*'
  40. ;
  41. ;               DX destroyed, other registers preserved
  42. ;
  43. ; At least one significant digit is always stored.
  44. ; Calling this function with a field width of zero
  45. ; results in an error return.
  46.  
  47.  
  48. DGROUP  group   _DATA
  49.  
  50.  
  51. _DATA   segment word public 'DATA'
  52.  
  53. buflen  equ     16              ; length of working buffers
  54.  
  55. buf1    db      buflen dup (?)  ; LTOA builds string here
  56. buf2    db      buflen dup (?)  ; formatted string built here
  57.  
  58. _DATA   ends
  59.  
  60.                                 ; names for local variables
  61. flags   equ     [bp-1]          ; formatting flags
  62. fpad    equ     [bp-2]          ; pad character, if any
  63. fdecpl  equ     [bp-3]          ; decimal places in output
  64. fwidth  equ     [bp-4]          ; width of output field
  65. fseg    equ     [bp-6]          ; segment of output field
  66. foffs   equ     [bp-8]          ; offset of output field
  67. fsign   equ     [bp-10]         ; sign of original number
  68.  
  69.  
  70. _TEXT   segment word public 'CODE'
  71.  
  72.         assume  cs:_TEXT
  73.  
  74.         extrn   LTOA:near       ; we will call the separately
  75.                                 ; assembled LTOA routine
  76.  
  77.         public  lcvt            ; make LCVT available to Linker
  78.  
  79. lcvt    proc    near            ; format 32-bit integer
  80.  
  81.         push    es              ; save registers
  82.         push    di
  83.         push    bp
  84.         push    cx
  85.         push    bx
  86.  
  87.         mov     bp,sp           ; set up local variables
  88.         sub     sp,10
  89.  
  90.         mov     fpad,cx         ; save flags and pad char.
  91.         mov     fwidth,bx       ; save width and dec. places
  92.         mov     fseg,ds         ; save output field segment
  93.         mov     foffs,si        ; save output field offset
  94.         mov     fsign,dx        ; save sign of number
  95.  
  96.         or      bl,bl           ; is output width zero?
  97.         jnz     lcvt01          ; no, proceed
  98.         jmp     lcvt15          ; error if width = zero
  99.  
  100. lcvt01: cmp     bh,(buflen+2)   ; too many decimal places?
  101.         jbe     lcvt02          ; no, proceed
  102.         jmp     lcvt14          ; error if buffer too small
  103.  
  104. lcvt02: or      dx,dx           ; test sign of number...
  105.         jns     lcvt03          ; jump if number positive
  106.  
  107.         neg     dx              ; negative, take abs. value
  108.         neg     ax              ; of number so we can control
  109.         sbb     dx,0            ; sign placement
  110.  
  111. lcvt03: mov     cx,10           ; use decimal base
  112.         mov     si,DGROUP       ; set DS:SI = local buffer
  113.         mov     ds,si
  114.         mov     si,offset DGROUP:buf1
  115.  
  116.         call    LTOA            ; convert DX:AX to ASCII
  117.                                 ; returns DS:SI -> string,
  118.                                 ;         AX = length
  119.  
  120.                                 ; now format the string...
  121.  
  122.         add     si,ax           ; point to end of string
  123.         dec     si              ; returned by LTOA
  124.         mov     cx,ax           ; let CX = string length
  125.  
  126.         push    ds              ; point to end of buffer
  127.         pop     es              ; for formatted string
  128.         mov     di,offset DGROUP:buf2+buflen-1
  129.  
  130.         std                     ; set direction flag
  131.                                 ; for backwards move
  132.         xor     bx,bx           ; init. places counter
  133.  
  134. lcvt04: movsb                   ; transfer one char.
  135.         inc     bx              ; count characters
  136.         cmp     bl,fdecpl       ; need decimal point?
  137.         jne     lcvt05          ; no, jump
  138.         mov     al,'.'          ; yes, store it
  139.         stosb
  140.  
  141. lcvt05: loop    lcvt04          ; until all chars. transferred
  142.  
  143.         cmp     bl,fdecpl       ; decimal taken care of?
  144.         ja      lcvt08          ; yes, jump
  145.  
  146.         je      lcvt07          ; well, partially...
  147.         
  148. lcvt06:                         ; no, need decimal point
  149.         mov     al,'0'          ; store zeros up to 
  150.         stosb                   ; decimal point
  151.         inc     bx
  152.         cmp     bl,fdecpl
  153.         jne     lcvt06
  154.         mov     al,'.'          ; store decimal point
  155.         stosb
  156.  
  157. lcvt07: mov     al,'0'          ; force leading zero
  158.         stosb
  159.  
  160. lcvt08:                         ; was number negative?
  161.         test    word ptr fsign,-1
  162.         jns     lcvt09          ; no, jump
  163.         mov     al,'-'          ; yes, store '-' sign
  164.         stosb
  165.         jmp     lcvt10
  166.  
  167. lcvt09:                         ; positive number, is
  168.                                 ; '+' sign needed?
  169.         test    byte ptr flags,20h
  170.         jz      lcvt10          ; no, jump
  171.         mov     al,'+'          ; yes, store '+' sign
  172.         stosb
  173.  
  174. lcvt10: cld                     ; string now formatted
  175.                                 ; with dec. point & sign
  176.         mov     si,di           ; copy address
  177.         inc     si              ; point to formatted string
  178.                                 ; and calculate its length
  179.         mov     ax,offset DGROUP:buf2+buflen
  180.         sub     ax,si           ; now AX = formatted length
  181.  
  182.         mov     es,fseg         ; set ES:DI = address and
  183.         mov     di,foffs        ; CX = length of user's 
  184.         mov     cl,fwidth       ; output buffer
  185.         xor     ch,ch
  186.  
  187.         jcxz    lcvt15          ; return error if output
  188.                                 ; field width = zero
  189.  
  190.         cmp     cx,ax           ; is string too big for
  191.                                 ; user's output field?
  192.         jae     lcvt11          ; no, jump
  193.  
  194.                                 ; OK to truncate string?
  195.         test    byte ptr flags,40h
  196.         jz      lcvt14          ; no, error has occurred
  197.  
  198.         mov     ax,cx           ; truncate formatted length
  199.                                 ; to output field length
  200.  
  201. lcvt11: push    ax              ; save formatted length
  202.  
  203.         mov     al,' '          ; default pad char = blank
  204.  
  205.                                 ; test special padding flag
  206.         test    byte ptr flags,10h
  207.         jz      lcvt12          ; jump if use ASCII blank
  208.  
  209.         mov     al,fpad         ; else use special char
  210.  
  211. lcvt12: rep stosb               ; flood output field with
  212.                                 ; padding character
  213.  
  214.         mov     di,foffs        ; restore output buffer address
  215.         pop     cx              ; length of formatted string
  216.  
  217.                                 ; left or right justify?
  218.         test    byte ptr flags,80h
  219.         jz      lcvt13          ; jump if left justify
  220.  
  221.         mov     al,fwidth       ; right justify, length of
  222.         xor     ah,ah           ; user's output buffer
  223.         sub     ax,cx           ; - formatted string length
  224.         add     di,ax           ; = offset into output field
  225.  
  226. lcvt13: rep movsb               ; transfer formatted string
  227.                                 ; to user's buffer
  228.  
  229.         clc                     ; success signal: clear Carry 
  230.         jmp     lcvt16          ; go clean up and exit
  231.  
  232. lcvt14:                         ; error encountered, fill
  233.                                 ; output field with '*' chars.
  234.  
  235.         mov     es,fseg         ; ES:DI -> output field
  236.         mov     di,foffs
  237.         mov     cl,fwidth       ; CX = output field length
  238.         xor     ch,ch           
  239.         mov     al,'*'          ; character = asterisk 
  240.         rep stosb               ; flood the output buffer
  241.  
  242. lcvt15: stc                     ; error signal: set Carry 
  243.  
  244. lcvt16: mov     ds,fseg         ; return DS:SI = address
  245.         mov     si,foffs        ; of output field
  246.         mov     al,fwidth       ; AX = output field width
  247.         mov     ah,0            ; (protect carry flag)
  248.  
  249.         mov     sp,bp           ; discard local variables
  250.  
  251.         pop     bx              ; restore registers
  252.         pop     cx
  253.         pop     bp
  254.         pop     di
  255.         pop     es
  256.  
  257.         ret                     ; back to caller
  258.  
  259. lcvt    endp
  260.  
  261.  
  262. _TEXT   ends
  263.  
  264.         end
  265.  
  266.